﻿using Microsoft.Extensions.DependencyInjection;
using Modules.BankSpecialAccount.Repositories;
using PmSoft;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Modules.BankSpecialAccount;

/// <summary>
/// 项目银行专户账号主键索引器
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class BankSpecialAccountIndexer
{
    private static readonly ConcurrentDictionary<int, string> idToKeyDict = new();
    private static readonly ConcurrentDictionary<string, int> keyToIdDict = new();
    private static readonly SemaphoreSlim _lock = new(initialCount: 1, maxCount: 1);

    private readonly BankSpecialAccountRepository specialAccountRepository;

    public BankSpecialAccountIndexer(BankSpecialAccountRepository specialAccountRepository)
    {
        this.specialAccountRepository = specialAccountRepository;
    }

    /// <summary>
    /// 根据专户ID获取专户账号
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string GetBankAccount(int id)
    {
        if (idToKeyDict.TryGetValue(id, out string? bankAccount))
            return bankAccount;

        try
        {
            _lock.Wait();

            if (idToKeyDict.TryGetValue(id, out bankAccount))
                return bankAccount;

            var specialAccount = specialAccountRepository.Get(id);
            if (specialAccount != null
                && !string.IsNullOrEmpty(specialAccount.BankNo)
                && idToKeyDict.TryAdd(id, specialAccount.BankNo))
            {
                return specialAccount.BankNo;
            }
            return string.Empty;
        }
        finally
        {
            _lock.Release();
        }
    }

    /// <summary>
    /// 根据专户账号获取专户ID
    /// </summary>
    /// <param name="bankAccount"></param>
    /// <returns></returns>
    public int? GetId(string bankAccount)
    {
        if (keyToIdDict.TryGetValue(bankAccount, out int id))
            return id;
        try
        {
            _lock.Wait();

            if (keyToIdDict.TryGetValue(bankAccount, out id))
                return id;

            int? bankAccountId = specialAccountRepository.GetProjectSpecialAccountIdByBankNo(bankAccount);
            if (bankAccountId.HasValue && bankAccountId > 0 && keyToIdDict.TryAdd(bankAccount, bankAccountId.Value))
                return bankAccountId.Value;

            return null;
        }
        finally
        {
            _lock.Release();
        }
    }

    public bool Remove(int id)
    {
        if (idToKeyDict.TryRemove(id, out string? key)
            && keyToIdDict.TryRemove(key, out _))
            return true;
        return false;
    }
}